unit database_start;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  Buttons, EditBtn, Menus, database_base, fpjson;

type

  { TDatabaseStartFrame }

  TDatabaseStartFrame = class(TDatabaseBaseFrame)
    AirshipPosEditButton: TEditButton;
    AirshipPosLabel: TLabel;
    ChangeBgButton: TButton;
    AddMenuItem: TMenuItem;
    EditMenuItem: TMenuItem;
    DeleteMenuItem: TMenuItem;
    PlayerPosEditButton: TEditButton;
    BoatPosEditButton: TEditButton;
    BoatPosLabel: TLabel;
    PartyPopupMenu: TPopupMenu;
    ShipPosEditButton: TEditButton;
    ShipPosLabel: TLabel;
    PositionGroupBox: TGroupBox;
    PlayerPosLabel: TLabel;
    StartsTransparentCheckBox: TCheckBox;
    ShowGameTitleCheckBox: TCheckBox;
    GameTitleBottomPanel: TPanel;
    PartyListBox: TListBox;
    PartyGroupBox: TGroupBox;
    GameTitleBgSpeedButton: TSpeedButton;
    TitlePartySplitter: TSplitter;
    TitleScreenGroupBox: TGroupBox;
    TopPanel: TPanel;

    procedure AddMenuItemClick(Sender: TObject);
    procedure ChangeBgButtonClick(Sender: TObject);
    procedure DeleteMenuItemClick(Sender: TObject);
    procedure EditMenuItemClick(Sender: TObject);
    procedure GameTitleBgSpeedButtonClick(Sender: TObject);
    procedure Init; override;
    procedure PartyListBoxDblClick(Sender: TObject);
    procedure PartyListBoxKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure PartyListBoxMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PlayerPosEditButtonKeyPress(Sender: TObject; var Key: char);
    procedure PosEditButtonClick(Sender: TObject);
    procedure UpdateEditButtons;
    procedure ShowGameTitleCheckBoxChange(Sender: TObject);
    procedure StartsTransparentCheckBoxChange(Sender: TObject);
  private
    IsLoading: Boolean;
    procedure UpdateTitleBackground;
    procedure UpdateStartingParty;
    function GetParentObject(StartingPosTag: Integer): TJSONObject;
    procedure DeleteSelectedPartyMember;
    function IsRealPartyMemberSelected: Boolean;
    function HasUnaddedPartyMembers: Boolean;
    procedure AddNewPartyMember;
    procedure EditSelectedPartyMember;
  public

  end;

resourcestring
  StartHeader = 'Start';
  rsAddNewPartyMember = '<Add new member>';

implementation

{$R *.lfm}

uses
  doublebackgroundselection, BGRABitmapTypes, globals, gameproject,
  Math, constants, mapplaceselectionunit, LCLType, partymemberselectionformunit;

{ TDatabaseStartFrame }

procedure TDatabaseStartFrame.Init;
begin
  IsLoading := True;
  ShowGameTitleCheckBox.Checked := Db.System.Booleans['optDrawTitle'];
  StartsTransparentCheckBox.Checked := Db.System.Booleans['optTransparent'];
  UpdateTitleBackground;
  UpdateStartingParty;
  UpdateEditButtons;
  IsLoading := False
end;

procedure TDatabaseStartFrame.PartyListBoxDblClick(Sender: TObject);
begin
  if IsRealPartyMemberSelected then
    EditSelectedPartyMember
  else if HasUnaddedPartyMembers then
    AddNewPartyMember;
end;

procedure TDatabaseStartFrame.PartyListBoxKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
  if Key = VK_DELETE then
    DeleteSelectedPartyMember;

  if Key = VK_RETURN then
    PartyListBoxDblClick(Sender);
end;

procedure TDatabaseStartFrame.PartyListBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then begin
    AddMenuItem.Enabled := HasUnaddedPartyMembers;
    EditMenuItem.Enabled := IsRealPartyMemberSelected;
    DeleteMenuItem.Enabled := IsRealPartyMemberSelected;

    PartyPopupMenu.PopUp
  end;
end;

procedure TDatabaseStartFrame.PlayerPosEditButtonKeyPress(Sender: TObject;
  var Key: char);
begin
  Key := #0;
  PosEditButtonClick(Sender);
end;

procedure TDatabaseStartFrame.PosEditButtonClick(Sender: TObject);
var
  ParentObject: TJSONObject;
  MapID: Integer = 0;
  MapIDJson: TJSONNumber;
  X: Integer = 0;
  Y: Integer = 0;
  XJson, YJson: TJSONNumber;
begin
  ParentObject := GetParentObject((Sender as TEditButton).Tag);

  if ParentObject.Find('startMapId', MapIDJson) then
    MapID := MapIDJson.AsInteger;

  if ParentObject.Find('startX', XJson) then
    X := XJson.AsInteger;

  if ParentObject.Find('startY', YJson) then
    Y := YJson.AsInteger;

  if MapPlaceSelectionForm.ShowSelection(MapID, X, Y, Db) then begin
    ParentObject.Integers['startMapId'] := MapPlaceSelectionForm.SelectedMapId;
    ParentObject.Integers['startX'] := MapPlaceSelectionForm.SelectedX;
    ParentObject.Integers['startY'] := MapPlaceSelectionForm.SelectedY;
  end;

  UpdateEditButtons
end;

procedure TDatabaseStartFrame.UpdateEditButtons;
  function FormatText(ParentObject: TJSONObject): String;
  var
    MapID: Integer = 0;
    MapIDJson: TJSONNumber;
    X: Integer = 0;
    Y: Integer = 0;
    XJson, YJson: TJSONNumber;
  begin
    if ParentObject.Find('startMapId', MapIDJson) then
      MapID := MapIDJson.AsInteger;

    if ParentObject.Find('startX', XJson) then
      X := XJson.AsInteger;

    if ParentObject.Find('startY', YJson) then
      Y := YJson.AsInteger;

    FormatText := Game.FormatPositionName(MapId, X, Y)
  end;

  procedure UpdateButton(Button: TEditButton);
  begin
    Button.Text := FormatText(GetParentObject(Button.Tag))
  end;

begin
  UpdateButton(PlayerPosEditButton);
  UpdateButton(BoatPosEditButton);
  UpdateButton(ShipPosEditButton);
  UpdateButton(AirshipPosEditButton)
end;

procedure TDatabaseStartFrame.ShowGameTitleCheckBoxChange(Sender: TObject);
begin
  if not IsLoading then
    Db.System.Booleans['optDrawTitle'] := ShowGameTitleCheckBox.Checked;
end;

procedure TDatabaseStartFrame.StartsTransparentCheckBoxChange(Sender: TObject);
begin
  if not IsLoading then
    Db.System.Booleans['optTransparent'] := StartsTransparentCheckBox.Checked;
end;

procedure TDatabaseStartFrame.UpdateTitleBackground;
var
  Bg1: String = '';
  Bg2: String = '';
  Bg1Json, Bg2Json: TJSONString;
  Background: TBGRACustomBitmap;
begin
  if (Db.System <> nil) and Db.System.Find('title1Name', Bg1Json) then
    Bg1 := Bg1Json.AsString;
  if (Db.System <> nil) and Db.System.Find('title2Name', Bg2Json) then
    Bg2 := Bg2Json.AsString;

  Background := Game.GetBackgroundBGRA(
             btTitle,
             Bg1,
             Bg2,
             Math.Min(
               {TODO: replace 20 with some way to find out glyph with }
               (GameTitleBgSpeedButton.Width - 20) / SCREEN_WIDTH,
               (GameTitleBgSpeedButton.Height - 20) / SCREEN_HEIGHT
             ));

  if Background <> nil then
    GameTitleBgSpeedButton.Glyph.Assign(Background)
  else
    GameTitleBgSpeedButton.Glyph.Clear;
end;

procedure TDatabaseStartFrame.UpdateStartingParty;
var
  PartyMembers: TJSONArray;
  I: Integer;
  SavedIndex: Integer;
begin
  SavedIndex := PartyListBox.ItemIndex;

  with PartyListBox.Items do begin
    BeginUpdate;
    Clear;

    if Db.System.Find('partyMembers', PartyMembers) then begin
      for I := 0 to PartyMembers.Count -1 do
        if PartyMembers[I].JSONType = jtNumber then
          Add(Db.GetActorName(PartyMembers.Integers[I], False));
      if HasUnaddedPartyMembers then
        Add(rsAddNewPartyMember);
    end;

    EndUpdate;
  end;

  PartyListBox.ItemIndex := SavedIndex;
end;

function TDatabaseStartFrame.GetParentObject(StartingPosTag: Integer
  ): TJSONObject;
begin
  if StartingPosTag = 0 then
    GetParentObject := Db.System
  else if StartingPosTag = 1 then
    GetParentObject := Db.System.Objects['boat']
  else if StartingPosTag = 2 then
    GetParentObject := Db.System.Objects['ship']
  else if StartingPosTag = 3 then
    GetParentObject := Db.System.Objects['airship']
  else
    GetParentObject := nil;
end;

procedure TDatabaseStartFrame.DeleteSelectedPartyMember;
begin
  if IsRealPartyMemberSelected then
    Db.System.Arrays['partyMembers'].Delete(PartyListBox.ItemIndex);

  UpdateStartingParty;
end;

function TDatabaseStartFrame.IsRealPartyMemberSelected: Boolean;
var
  LastIsSelected, NoneIsSelected: Boolean;
begin
  LastIsSelected := PartyListBox.ItemIndex >= PartyListBox.Items.Count - 1;
  NoneIsSelected := PartyListBox.ItemIndex < 0;

  IsRealPartyMemberSelected := not LastIsSelected and not NoneIsSelected;
end;

function TDatabaseStartFrame.HasUnaddedPartyMembers: Boolean;
begin
  HasUnaddedPartyMembers := Db.System.Arrays['partyMembers'].Count
                            < Db.Actors.Count - 1;
end;

procedure TDatabaseStartFrame.AddNewPartyMember;
var
  NewId: Integer = -1;
begin
  NewId := PartyMemberSelectionForm.SelectPartyMember(
    Db, -1, Db.System.Arrays['partyMembers']
  );
  if NewId > 0 then
    Db.System.Arrays['partyMembers'].Insert(PartyListBox.ItemIndex, NewId);

  UpdateStartingParty
end;

procedure TDatabaseStartFrame.EditSelectedPartyMember;
var
  Index: Integer;
  NewId: Integer = -1;
begin
  Index := PartyListBox.ItemIndex;

  NewId := PartyMemberSelectionForm.SelectPartyMember(
    Db,
    Db.System.Arrays['partyMembers'].Integers[Index],
    Db.System.Arrays['partyMembers']
  );
  if NewId > 0 then
    Db.System.Arrays['partyMembers'].Integers[Index] := NewId;

  UpdateStartingParty
end;

procedure TDatabaseStartFrame.ChangeBgButtonClick(Sender: TObject);
var
  Bg1: String = '';
  Bg2: String = '';
  Bg1Json, Bg2Json: TJSONString;
begin
  if (Db.System <> nil) and Db.System.Find('title1Name', Bg1Json) then
    Bg1 := Bg1Json.AsString;
  if (Db.System <> nil) and Db.System.Find('title2Name', Bg2Json) then
    Bg2 := Bg2Json.AsString;

  with DoubleBackgroundSelectionForm do
    if ShowTitleBgSelection(Bg1, Bg2) then begin
      Db.System.Strings['title1Name'] := SelectedBgs[1];
      Db.System.Strings['title2Name'] := SelectedBgs[2];
      UpdateTitleBackground;
    end;
end;

procedure TDatabaseStartFrame.AddMenuItemClick(Sender: TObject);
begin
  AddNewPartyMember
end;

procedure TDatabaseStartFrame.DeleteMenuItemClick(Sender: TObject);
begin
  DeleteSelectedPartyMember
end;

procedure TDatabaseStartFrame.EditMenuItemClick(Sender: TObject);
begin
  EditSelectedPartyMember
end;

procedure TDatabaseStartFrame.GameTitleBgSpeedButtonClick(Sender: TObject);
begin
  ChangeBgButton.Click
end;

end.

